package controlmercancias.gui.cliente;

import controlmercancias.excepciones.ForceExitException;
import controlmercancias.gui.WaitingJFrame;
import controlmercancias.remoto.cliente.Cliente;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTable;
import javax.swing.ListModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

public class DatosTren extends JFrame {

    private static final long serialVersionUID = 1L;
    private static Font font = new Font(null, Font.BOLD, 14);
    private JTextField usuario;
    private JTextField estadoTren;
    private JList listaTrenes;
    private String ultimoTren;
    private JCheckBox gpsConectado;
    private JTable tablaSensores;
    private JButton verSensor;
    private JButton actualizarSensor;
    private JButton cerrarSesion;
    private JButton actualizar;
    private JLabel informacion;
    private JTextField ultimaPosGps;
    private JButton getPosGps;
    private JLabel icono;
    private HashMap<String, ImageIcon> cacheIconos;
    private DefaultTableCellRenderer tableCellRenderer = new DefaultTableCellRenderer() {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, final int column) {
            if (column == 2) {
                JPanel jp = new JPanel(new FlowLayout(FlowLayout.CENTER));
                if (isSelected) {
                    jp.setBackground(Color.green.darker());
                } else {
                    jp.setBackground(new Color(0, 0, 0, 0));
                }
                jp.setBorder(BorderFactory.createEmptyBorder(-5, -5, -5, -5));
                JCheckBox check = new JCheckBox("", ((String) value).equals("ON"));
                jp.add(check);
                return jp;
            }
            Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (isSelected) {
                c.setBackground(Color.green.darker());
            } else {
                c.setBackground(null);
            }
            return c;
        }
    };

    public DatosTren() {

        this.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                try {
                    Cliente.salir();
                } catch (Exception ex) {
                }
                super.windowClosing(e);
            }
        });
        this.setTitle("Control ferroviario");
        this.setLayout(new BorderLayout());
        String name = Cliente.getUserName();
        usuario = new JTextField(name, name.length());
        usuario.setEditable(false);
        estadoTren = new JTextField(20);
        estadoTren.setEditable(false);
        listaTrenes = new JList();
        listaTrenes.setCellRenderer(new DefaultListCellRenderer() {

            private static final long serialVersionUID = 1L;

            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                if (isSelected) {
                    c.setBackground(Color.green.darker());
                } else {
                    c.setBackground(null);
                }
                return c;
            }
        });
        listaTrenes.addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {
                String id = ((String) listaTrenes.getSelectedValue()).trim();
                if (id.equals(ultimoTren)) {
                    return;
                }
                try {
                    Cliente.setTren(id);
                    refresh(false);
                    String t = Cliente.getTrenActual();
                    ultimoTren = t;
                    setInformationMessage("Mostrando tren con id " + id);
                } catch (IOException ex) {
                    setErrorMessage(ex.getMessage());
                } catch (ForceExitException ex) {
                    forcedToExit(ex);
                }
            }
        });
        tablaSensores = new JTable() {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        tablaSensores.setRowHeight(20);
        tablaSensores.setAutoCreateRowSorter(true);
        tablaSensores.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
        tablaSensores.setColumnSelectionAllowed(false);
        tablaSensores.setDragEnabled(false);
        tablaSensores.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                int column = tablaSensores.getSelectedColumn();
                if (column == 2) {
                    int row = tablaSensores.getSelectedRow();
                    String estado = (String) tablaSensores.getValueAt(row, column);
                    int id = Integer.parseInt((String) tablaSensores.getValueAt(row, 0));
                    try {
                        if (estado.equals("OFF")) {
                            Cliente.on(id);
                            tablaSensores.setValueAt("ON", row, column);
                        } else {
                            Cliente.off(id);
                            tablaSensores.setValueAt("OFF", row, column);
                        }
                        setInformationMessage("Actualización de sensor con id " + id + " completa");
                    } catch (IOException ex) {
                        setErrorMessage(ex.getMessage());
                    } catch (ForceExitException ex) {
                        forcedToExit(ex);
                    }
                }
            }
        });
        gpsConectado = new JCheckBox();
        gpsConectado.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            if (e.getStateChange() == ItemEvent.SELECTED) {
                                Cliente.onGps();
                            } else {
                                Cliente.offGps();
                            }
                            setInformationMessage("Actualización de GPS completada");
                        } catch (IOException ex) {
                            setErrorMessage(ex.getMessage());
                        } catch (ForceExitException ex) {
                            forcedToExit(ex);
                        }
                    }
                });
            }
        });
        verSensor = new JButton("Ver detalles de sensor");
        verSensor.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int row = tablaSensores.getSelectedRow();
                if (row == -1) {
                    JOptionPane.showMessageDialog(DatosTren.this, "Selecciona un sensor para ver sus datos", "Selecciona un sensor", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                int id = Integer.parseInt((String) tablaSensores.getModel().getValueAt(row, 0));
                try {
                    String historico = Cliente.historico(id);
                    DatosSensor ds = new DatosSensor(id + "", historico);
                    ds.setVisible(true);
                } catch (ForceExitException ex) {
                    forcedToExit(ex);
                } catch (IOException ex) {
                    setErrorMessage(ex.getMessage());
                }
            }
        });
        actualizarSensor = new JButton("Actualizar sensor");
        actualizarSensor.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int row = tablaSensores.getSelectedRow();
                if (row == -1) {
                    JOptionPane.showMessageDialog(DatosTren.this, "Selecciona un sensor para actualizarlo", "Selecciona un sensor", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                actualizarSensor.setEnabled(false);
                TimerTask tt = new TimerTask() {

                    @Override
                    public void run() {
                        actualizarSensor.setEnabled(true);
                    }
                };
                new Timer().schedule(tt, 1000);
                int id = Integer.parseInt((String) tablaSensores.getModel().getValueAt(row, 0));
                try {
                    String valor = Cliente.getValact(id);
                    tablaSensores.setValueAt(valor.replaceAll(";", " ; "), row, 3);
                    setInformationMessage("Actualización de sensor con id " + id + " completa");
                } catch (ForceExitException ex) {
                    forcedToExit(ex);
                } catch (IOException ex) {
                    setErrorMessage(ex.getMessage());
                }
            }
        });
        cerrarSesion = new JButton("Cerrar sesion");
        cerrarSesion.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                DatosTren.this.setEnabled(false);
                DatosTren.this.dispose();
                DatosTren.this.processWindowEvent(new WindowEvent(DatosTren.this, WindowEvent.WINDOW_CLOSING));
            }
        });
        actualizar = new JButton("Actualización de configuración");
        actualizar.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                final JDialog jd = new JDialog(DatosTren.this);
                jd.setTitle("Contraseña");
                jd.setLayout(new BorderLayout(0, 10));
                jd.add(new JLabel("Introduce tu contraseña de actualizaciones:"), BorderLayout.NORTH);
                JPasswordField pass = new JPasswordField(20);
                jd.add(pass, BorderLayout.CENTER);
                final JButton aceptar = new JButton("Aceptar");
                aceptar.addActionListener(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        jd.setEnabled(false);
                        jd.dispose();
                        jd.setUndecorated(true);
                    }
                });
                pass.addKeyListener(new KeyAdapter() {

                    @Override
                    public void keyTyped(KeyEvent e) {
                        if (e.getKeyChar() == '\n') {
                            aceptar.doClick();
                        }
                    }
                });
                JPanel jp = new JPanel(new FlowLayout(FlowLayout.CENTER));
                jp.add(aceptar);
                jd.add(jp, BorderLayout.SOUTH);
                jd.setModalityType(ModalityType.APPLICATION_MODAL);
                jd.setSize(250, 130);
                jd.setResizable(false);
                jd.setLocationRelativeTo(null);
                jd.setVisible(true);
                if (!jd.isUndecorated()) {
                    return;
                }
                String p = "";
                for (char s : pass.getPassword()) {
                    p += s;
                }
                final String str = p;
                final WaitingJFrame wait = new WaitingJFrame("Espere mientras se actualiza la configuración...");
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        wait.setVisible(true);
                    }
                });
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            setInformationMessage(Cliente.actualizar(Cliente.getUserName(), str));
                        } catch (ForceExitException ex) {
                            forcedToExit(ex);
                        } catch (IOException ex) {
                            setErrorMessage(ex.getMessage());
                        } catch (Exception ex) {
                            setErrorMessage(ex.getMessage());
                        }
                        wait.setVisible(false);
                        wait.setEnabled(false);
                        wait.dispose();
                    }
                }).start();
            }
        });
        informacion = new JLabel();
        informacion.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        ultimaPosGps = new JTextField(12);
        ultimaPosGps.setEditable(false);
        getPosGps = new JButton("Obtener posición");
        getPosGps.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        String ultPosGps = ultimaPosGps.getText();
                        try {
                            ultimaPosGps.setText(Cliente.getPosGps().replace("�", "º")); //.replace("�", "º")
                            setInformationMessage("Posición obtenida");
                        } catch (ForceExitException ex) {
                            forcedToExit(ex);
                        } catch (IOException ex) {
                            ultimaPosGps.setText(ultPosGps);
                            setErrorMessage(ex.getMessage());
                        }
                    }
                }).start();
            }
        });
        icono = new JLabel();
        cacheIconos = new HashMap<String, ImageIcon>();

        JPanel north = new JPanel(new BorderLayout());
        JPanel jp = new JPanel();
        BoxLayout boxLayout = new BoxLayout(jp, BoxLayout.Y_AXIS);
        jp.setLayout(boxLayout);
        JScrollPane jsp = new JScrollPane(listaTrenes, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        jsp.setMaximumSize(new Dimension(200, 100));
        jp.add(new JLabel("Lista de trenes:"));
        jp.add(jsp);
        jp.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
        north.add(jp, BorderLayout.EAST);
        north.add(panelIzquierdo(), BorderLayout.CENTER);
        north.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
        this.add(north, BorderLayout.NORTH);
        jp = new JPanel(new BorderLayout());
        jsp = new JScrollPane(tablaSensores, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        jsp.setBorder(BorderFactory.createTitledBorder("Lista de sensores"));
        jp.add(jsp, BorderLayout.CENTER);
        JPanel s = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 0));
        s.add(verSensor);
        s.add(actualizarSensor);
        jp.add(s, BorderLayout.SOUTH);
        this.add(jp, BorderLayout.CENTER);
        informacion.setFont(font);
        this.add(informacion, BorderLayout.SOUTH);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        refresh(true);
        ultimoTren = Cliente.getTrenActual();
        listaTrenes.setSelectedValue(Cliente.getTrenActual(), true);
        this.setSize(new Dimension(800, 600));
        this.setResizable(false);
        this.setLocationRelativeTo(null);
        this.setIconImage(Cliente.appIcon);
    }

    private JPanel panelIzquierdo() {
        JPanel izquierdo = new JPanel();
        BoxLayout boxLayout = new BoxLayout(izquierdo, BoxLayout.Y_AXIS);
        izquierdo.setLayout(boxLayout);
        JPanel panelAux = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
        panelAux.add(new JLabel("Usuario:"));
        panelAux.add(usuario);
        panelAux.add(cerrarSesion);
        panelAux.add(actualizar);
        izquierdo.add(panelAux);
        panelAux = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
        panelAux.add(new JLabel("Estado tren:"));
        panelAux.add(estadoTren);
        icono = new JLabel(new ImageIcon(getClass().getResource("/controlmercancias/resources/funcionando.gif")));
        panelAux.add(icono);
        izquierdo.add(panelAux);
        panelAux = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        panelAux.setBorder(BorderFactory.createTitledBorder("GPS"));
        panelAux.add(new JLabel("Conectado:"));
        panelAux.add(gpsConectado);
        panelAux.add(new JLabel("Última posición del tren:"));
        panelAux.add(ultimaPosGps);
        panelAux.add(getPosGps);
        izquierdo.add(panelAux);
        return izquierdo;
    }

    private void cargarListaTrenes(List<String> trenes) {
        String[] array = new String[trenes.size()];
        for (int i = 0; i < trenes.size(); i++) {
            array[i] = trenes.get(i);
        }
        listaTrenes.setListData(array);
    }

    private void cargarTablaSensores(List<String> sensores) throws ForceExitException, IOException {
        DefaultTableModel lm = new DefaultTableModel(new String[]{"ID", "Descripción", "Estado", "Último valor"}, 0);
        for (String s : sensores) {
            String[] split = s.split(";");
            int id = Integer.parseInt(split[0]);
            String val = Cliente.getValact(id);
            lm.addRow(new String[]{split[0], split[1], split[2], val.replaceAll(";", " ; ")});
        }
        tablaSensores.setModel(lm);
        tablaSensores.getColumnModel().getColumn(2).setMaxWidth(80);
        tablaSensores.getColumnModel().getColumn(3).setMinWidth(150);
        for (int i = 0; i < tablaSensores.getColumnCount(); i++) {
            tablaSensores.getColumnModel().getColumn(i).setCellRenderer(tableCellRenderer);
        }
        tablaSensores.getTableHeader().setReorderingAllowed(false);
    }

    public void refresh(final boolean todo) {
        final WaitingJFrame w = new WaitingJFrame("Actualizando trenes...");
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                w.setVisible(true);
            }
        });

        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                if (todo) {
                    ListModel listModel = listaTrenes.getModel();
                    Object selected = listaTrenes.getSelectedValue();
                    try {
                        cargarListaTrenes(Cliente.getTrenesDeUsuario());
                    } catch (ForceExitException ex) {
                        forcedToExit(ex);
                    } catch (IOException ex) {
                        listaTrenes.setModel(listModel);
                        listaTrenes.setSelectedValue(selected, true);
                    }
                }
                TableModel tableModel = tablaSensores.getModel();
                boolean gpsConn = gpsConectado.isSelected();
                String estado = estadoTren.getText();
                try {
                    cargarTablaSensores(Cliente.listsensor());
                    gpsConectado.setSelected("ON".equals(Cliente.getGps()));
                    String s = Cliente.estado();
                    estadoTren.setText(s);
                    ImageIcon get = cacheIconos.get(s);
                    if (get != null) {
                        icono.setIcon(get);
                    } else {
                        ImageIcon ii = new ImageIcon(DatosTren.class.getResource("/controlmercancias/resources/" + s.toLowerCase() + ".gif"));
                        icono.setIcon(ii);
                        cacheIconos.put(s, ii);
                    }
                    ultimaPosGps.setText(Cliente.getPosGps().replace("�", "º")); //.replace("�", "º")
                    setInformationMessage("Actualización completa");
                } catch (ForceExitException ex) {
                    forcedToExit(ex);
                } catch (IOException ex) {
                    tablaSensores.setModel(tableModel);
                    gpsConectado.setSelected(gpsConn);
                    estadoTren.setText(estado);
                    setErrorMessage(ex.getMessage());
                }
                w.setVisible(false);
                w.setEnabled(false);
                w.dispose();
            }
        });
        t.start();
    }

    private void forcedToExit(ForceExitException ex) {
        JOptionPane.showMessageDialog(DatosTren.this, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        DatosTren.this.setEnabled(false);
        DatosTren.this.dispose();
    }

    private void setErrorMessage(String s) {
        informacion.setForeground(Color.red);
        informacion.setText(s);
    }

    private void setInformationMessage(String s) {
        informacion.setForeground(Color.black);
        informacion.setText(s);
    }
}
